﻿using System;

namespace Patterns.AbstractFactory {

    public class AppliedExample {

        public static void Run() {
            // Create and run the Africa animal world
            ContinentFactory africa = new AfricaFactory();
            AnimalWorld africaWorld = new AnimalWorld(africa);
            africaWorld.RunFoodChain();

            // Create and run the America animal world
            ContinentFactory america = new AmericaFactory();
            AnimalWorld americaWorld = new AnimalWorld(america);
            americaWorld.RunFoodChain();
        }

        // "AbstractFactory"
        private abstract class ContinentFactory {
            public abstract Herbivore CreateHerbivore();
            public abstract Carnivore CreateCarnivore();
        }

        // "ConcreteFactory1"
        private class AfricaFactory : ContinentFactory {
            public override Herbivore CreateHerbivore() {
                return new Wildebeest();
            }
            public override Carnivore CreateCarnivore() {
                return new Lion();
            }
        }

        // "ConcreteFactory2"
        private class AmericaFactory : ContinentFactory {
            public override Herbivore CreateHerbivore() {
                return new Bison();
            }
            public override Carnivore CreateCarnivore() {
                return new Wolf();
            }
        }

        // "AbstractProductA"
        private abstract class Herbivore { }

        // "AbstractProductB"
        private abstract class Carnivore {
            public abstract void Eat(Herbivore h);
        }

        // "ProductA1"
        private class Wildebeest : Herbivore { }

        // "ProductB1"
        private class Lion : Carnivore {
            public override void Eat(Herbivore h) {
                // Eat Wildebeest
                Console.WriteLine(this.GetType().Name +
                  " eats " + h.GetType().Name);
            }
        }

        // "ProductA2"
        private class Bison : Herbivore {
        }

        // "ProductB2"
        private class Wolf : Carnivore {
            public override void Eat(Herbivore h) {
                // Eat Bison
                Console.WriteLine(this.GetType().Name +
                  " eats " + h.GetType().Name);
            }
        }

        // "Client"
        private class AnimalWorld {
            private Herbivore Herbivore { get; set; }
            private Carnivore Carnivore { get; set; }

            // Constructor
            public AnimalWorld(ContinentFactory factory) {
                Carnivore = factory.CreateCarnivore();
                Herbivore = factory.CreateHerbivore();
            }

            public void RunFoodChain() {
                Carnivore.Eat(Herbivore);
            }
        }
    }
}
